#include "Renderer.h"
#include "RenderCommand.h"
#include "Fysics/System/ResourceManager.h"

#include <glm/gtc/matrix_transform.hpp>

namespace Fysics
{
	Renderer::RenderData Renderer::m_Data = Renderer::RenderData();

	void Renderer::Init()
	{
		m_Data.screenRenderViewMatrix = glm::lookAt({ 0.f, 0.f, 3.5f }, glm::vec3(0), { 0, 1, 0 });
	}

	void Renderer::Destroy()
	{
		RenderCommand::DeleteExecutant();
	}

	void Renderer::BeginScene(const ViewCamera& camera)
	{
		RenderCommand::Clear();
		RenderCommand::OpenDepthTest();
		m_Data.projectionMatrix = camera.GetProjectionMatrix();
		m_Data.viewMatrix = camera.GetViewMatrix();
		m_Data.modelMatrix = glm::mat4(1.0f);
	}

	void Renderer::EndScene()
	{

	}

	void Renderer::BeginScreen(const ViewCamera& camera)
	{
		RenderCommand::CloseDepthTest();
		m_Data.projectionMatrix = camera.GetProjectionMatrix();
		m_Data.viewMatrix = m_Data.screenRenderViewMatrix;
		m_Data.modelMatrix = glm::mat4(1.0f);
	}

	void Renderer::EndScreen()
	{
	}

	void Renderer::SetRenderSide(int side, int screenWidth, int screenHeight)
	{
		RenderCommand::RenderSide(side, screenWidth, screenHeight);
	}

	void Renderer::SubmitModelMatrix(const glm::mat4& modelMatrix)
	{
		m_Data.modelMatrix = modelMatrix;
	}

	void Renderer::Submit(const ShaderProgram* shaderProgram, const VertexArray* vertexArray)
	{
		if (vertexArray == nullptr)
			return;

		if (shaderProgram == nullptr)
			return;

		shaderProgram->Bind();
		shaderProgram->UploadUniform("u_Transform",
			m_Data.projectionMatrix *
			m_Data.viewMatrix *
			m_Data.modelMatrix);

		vertexArray->Bind();
		RenderCommand::DrawIndexed(vertexArray);
	}

	void Renderer::DrawLine(const ShaderProgram* shaderProgram, const VertexArray* vertexArray, 
		int width, const glm::vec4& color)
	{
		if (vertexArray == nullptr)
			return;

		if (shaderProgram == nullptr)
			return;

		shaderProgram->Bind();
		shaderProgram->UploadUniform("u_Transform",
			m_Data.projectionMatrix *
			m_Data.viewMatrix *
			m_Data.modelMatrix);
		shaderProgram->UploadUniform("u_Color", color);

		RenderCommand::DrawLine(vertexArray, width);
	}

	void Renderer::DrawPoints(const ShaderProgram* shaderProgram, const VertexArray* vertexArray, 
		int radius, const glm::vec4& color)
	{
		if (vertexArray == nullptr)
			return;

		if (shaderProgram == nullptr)
			return;

		shaderProgram->Bind();
		shaderProgram->UploadUniform("u_Transform",
			m_Data.projectionMatrix *
			m_Data.viewMatrix *
			m_Data.modelMatrix);
		shaderProgram->UploadUniform("u_Color", color);

		RenderCommand::DrawPoints(vertexArray, radius);
	}
}